package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.user.client.impl.UserDegradeFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mysql.cj.x.protobuf.MysqlxCrud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.annotation.ElementType;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private VodService vodService;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Override
    //确定事务，就是都只能一起完成，不能中断其中的一个
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
        //1.拷贝声音属性到声音PO对象 属性赋值
        TrackInfo trackInfo = BeanUtil.copyProperties(trackInfoVo, TrackInfo.class);
        //2.属性赋值
        trackInfo.setUserId(userId);
        trackInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
        //2.1 查询点播服务获取声音媒体相关信息
        TrackMediaInfoVo trackMediaInfoVo = vodService.getTrackMediaInfo(trackInfo.getMediaFileId());
        trackInfo.setMediaType(trackMediaInfoVo.getType());
        trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfoVo.getDuration()));
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        //2.2 查询声音列表设置声音序号
        // 获取专辑最后一条声音记录
        int orderNum = 1;
        LambdaQueryWrapper<TrackInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(TrackInfo::getAlbumId, userId).orderByDesc(TrackInfo::getId).last("limit 1");

        TrackInfo trackInfo1 = trackInfoMapper.selectOne(lambdaQueryWrapper);
        if (trackInfo1 != null) {
            orderNum = trackInfo1.getOrderNum() + 1;
        }
        trackInfo.setOrderNum(orderNum);
        //2.3 保存声音记录
        trackInfoMapper.insert(trackInfo);
        //3.更新专辑声音总数
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        albumInfo.setIncludeTrackCount(trackInfo.getOrderNum() + 1);
        albumInfoMapper.updateById(albumInfo);
        //4.初始化声音统计信息
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);
    }

    @Override
    public void saveTrackStat(Long id, String trackStatPlay) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(id);
        trackStat.setStatType(trackStatPlay);
        trackStat.setStatNum(0);
        trackStatMapper.insert(trackStat);
    }

    @Override
    public Page<TrackListVo> findUserTrackPage(Page<TrackListVo> trackListVoPage, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.findUserTrackPage(trackListVoPage, trackInfoQuery);
    }

    @Override
    public void updateTrackInfo(long id, TrackInfoVo trackInfoVo) {
        //根据声音ID查询声音对象
        TrackInfo trackInfo = this.getById(id);
        //判断声音是否进行了修改，如果修改则重新设置音频相关信息
        //trackInfoVo 这个是新的声音，trackinfo是数据库里面的声音
        if (!trackInfoVo.getMediaFileId().equals(trackInfo.getMediaFileId())) {
            //说明音频文件发生了修改
            TrackMediaInfoVo trackMediaInfoVo = vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId());
            if (trackMediaInfoVo == null) {
                throw new GuiguException(ResultCodeEnum.VOD_FILE_ID_ERROR);
            }
            trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfoVo.getDuration()));
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
        }
        //拷贝声音VO对象到声音PO对象中
        BeanUtil.copyProperties(trackInfoVo, trackInfo);
        //更新声音媒体
        this.updateById(trackInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long trackId) {

        TrackInfo trackInfo = this.getById(trackId);
        //删掉状态中的声音的信息
        trackInfoMapper.deleteById(trackId);


        //删掉专辑中的声音的信息
        //先得到声音信息中的专辑的id
        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        Integer includeTrackCount = albumInfo.getIncludeTrackCount() - 1;
        albumInfo.setIncludeTrackCount(includeTrackCount);
        albumInfoMapper.updateById(albumInfo);

        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));

        //删掉云上的声音的信息
        String mediaFileId = trackInfo.getMediaFileId();
        vodService.deleteMediaFile(mediaFileId);
    }

    @Override
    public Page<AlbumTrackListVo> getUserAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long userId, Long albumId) {
        //1.根据声音id查询声音的分页列表信息
        pageInfo = trackInfoMapper.getUserAlbumTrackPage(pageInfo, albumId);
        List<AlbumTrackListVo> trackList = pageInfo.getRecords();


        //2.根据专辑ID查询专辑信息-得到专辑付费类型以及免费试听集数（VIP免费或者付费才有）
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //2.1 获取专辑付费类型 0101-免费、0102-vip免费、0103-付费
        String payType = albumInfo.getPayType();

        //3.用户未登录
        if (userId == null) {
            // 3.1 专辑付费类型为：0102-vip免费 或者 0103-付费
            if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(payType)) {
                //3.2 将当前页中声音列表获取到，找出非试听声音列表，为非试听声音设置“付费”标识
                trackList.stream().filter(trackInfo -> {
                    //声音序号大于>免费试听集数 就得到需要付费的声音
                    return trackInfo.getOrderNum() > albumInfo.getTracksForFree();
                }).collect(Collectors.toList()).stream().forEach(trackInfo -> {
                    //除了试听的声音外，其他的声音全部设置为：付费
                    trackInfo.setIsShowPaidMark(true);
                });
            }
        } else {
            //4.用户已登录  如果登录为普通用户或VIP过期了->未购买专辑未购买相关声音，将声音设置为付费标识；付费的专辑->未购买相关专辑或相关声音，将声音设置为付费
            //4.1 远程调用用户微服务获取用户信息（VIP状态）
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            //声明变量是否需要购买
            boolean isNeedPay = false;
            //4.2 付费类型：VIP免费-->普通用户或者VIP过期 进一步查看用户是否购买过专辑或者声音
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType)) {
                if (userInfoVo.getIsVip().intValue() == 0) {
                    //普通用户
                    isNeedPay = true;
                }
                if (userInfoVo.getIsVip().intValue() == 1 && userInfoVo.getVipExpireTime().before(new Date())) {
                    //VIP会员 会员过期- 会员到期时间 在 当前时间之前  -- 后期会有延迟任务更新会员过期时间
                    isNeedPay = true;
                }
            } else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
                //4.3 付费类型：付费-->通用户或者VIP,进一步查看用户是否购买过专辑或者声音
                isNeedPay = true;
            }


            //5.统一处理需要购买情况：如果用户未购买专辑或者声音，将声音付费标识改为：true
            if (isNeedPay) {
                //5.1 得到当前页中声音列表--需要将免费试听集数过滤掉
                List<AlbumTrackListVo> trackListVoList = trackList.stream().filter(trackInfo -> {
                    //将试听的集数过滤掉
                    return trackInfo.getOrderNum() > albumInfo.getTracksForFree();
                }).collect(Collectors.toList());

                //需要进一步验证用户购买情况声音ID
                List<Long> trackIdList =
                        trackListVoList.stream().map(AlbumTrackListVo::getTrackId).collect(Collectors.toList());

                //5.2 远程调用用户微服务-查询当前页中声音列表购买情况Map<声音ID，购买状态>
                Map<Long, Integer> buyStatusMap =
                        userFeignClient.userIsPaidTrackList(userId, albumId, trackIdList).getData();

                //5.3 如果当前页中声音未购买 将指定声音付费标识改为：true
                for (AlbumTrackListVo albumTrackListVo : trackListVoList) {
                    //获取声音购买结果
                    Integer isBuy = buyStatusMap.get(albumTrackListVo.getTrackId());
                    if (isBuy == 0) {
                        //说明当前用户未购买该专辑或者该声音
                        albumTrackListVo.setIsShowPaidMark(true);
                    }
                }
            }
        }

        return pageInfo;
    }

    /**
     * 更新声音统计信息
     *
     * @param albumId  专辑ID
     * @param trackId  声音ID
     * @param statType 统计类型
     * @param count    数量
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStat(Long albumId, Long trackId, String statType, Integer count) {
        //1.更新声音统计信息
        trackStatMapper.updateStat(trackId, statType, count);

        //2.更新专辑统计信息（如果是声音播放量或者声音评论量同步修改专辑统计信息）
        if (SystemConstant.TRACK_STAT_PLAY.equals(statType)) {
            //TODO 主要要将播放的统计类型 改为 声音的统计类型 “0401”
            albumStatMapper.updateStat(albumId, SystemConstant.ALBUM_STAT_PLAY, count);
        }
        if (SystemConstant.TRACK_STAT_COMMENT.equals(statType)) {
            //TODO 主要要将播放的统计类型 改为 声音的统计类型 “0404”
            albumStatMapper.updateStat(albumId, SystemConstant.ALBUM_STAT_COMMENT, count);
        }
    }

    /**
     * 根据声音ID，查询声音统计信息
     *
     * @param trackId
     * @return
     */
    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        return trackInfoMapper.getTrackStatVo(trackId);
    }


    /**
     * 查询当前用户分集购买声音列表
     *
     * @param userId
     * @param trackId
     * @return
     */
    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long userId, Long trackId) {
        //1.根据声音ID查询声音对象（用于获取专辑ID）
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        Assert.notNull(trackInfo, "声音信息为空");
        //2.根据专辑ID+当前选中声音序号（序号大于等于当前声音序号声音列表），按照序号正序排-得到“待购”声音集合
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId());
        queryWrapper.ge(TrackInfo::getOrderNum, trackInfo.getOrderNum());
        queryWrapper.orderByAsc(TrackInfo::getOrderNum);
        List<TrackInfo> waitBuyTrackInfoList = trackInfoMapper.selectList(queryWrapper);

        //3.远程调用服务，根据专辑id获取用户声音的id的列表信息
        List<Long> paidTrackList = userFeignClient.getUserPaidTrackList(trackInfo.getAlbumId()).getData();

        //4.将已购声音ID排除到分集购买以外
        if (CollectionUtil.isNotEmpty(paidTrackList)) {
            //用户已买过当前专辑下声音，过滤条件：待购声音对象ID没有出现在已购声音ID集合中得到未买声音 contains (包含)
            waitBuyTrackInfoList.stream().filter(trackInfo1 -> !paidTrackList.contains(trackInfo1.getId())).collect(Collectors.toList());
        }
        //5.对预购的声音ID集合处理，动态展示“分集购买对象” 例如：本集、 后10集、后18集
        List<Map<String, Object>> list = new ArrayList<>();
        //5.1获取待购买的声音的数量
        int count = waitBuyTrackInfoList.size();

        //5.2获取声音的单价
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        BigDecimal price = albumInfo.getPrice();

        //5.3 获取本集要购买的
        Map<String, Object> currMap = new HashMap<>();
        currMap.put("name", "本集");
        currMap.put("price", price);
        currMap.put("trackCount", 1);
        list.add(currMap);

        //判断 待购声音数量>10、20、30、40、50 则固定显示后 i 集
        for (int i = 10; i <= 50; i += 10) {
            if (count > i) {
                BigDecimal totalPrice = price.multiply(new BigDecimal(i));
                Map<String, Object> list1 = new HashMap<>();
                list1.put("name", "后" + i + "集");
                list1.put("price", totalPrice);
                list1.put("trackCount", i);
                list.add(list1);
            } else {
                BigDecimal totalPrice = price.multiply(new BigDecimal(count));
                Map<String, Object> list1 = new HashMap<>();
                list1.put("name", "后" + count + "集");
                list1.put("price", totalPrice);
                list1.put("trackCount", count);
                list.add(list1);
                break;
            }
        }
        return list;
    }

    /**
     * 查询当前用户待购声音列表-用于渲染声音结算页面
     *
     * @param userId
     * @param trackId
     * @param trackCount
     * @return
     */
    @Override
    public List<TrackInfo> findPaidTrackInfoList(Long userId, Long trackId, Long trackCount) {
        //1.根据声音id获取声音对象（用于获取专辑）
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        Assert.notNull(trackInfo, "声音不存在");

        //2.根据专辑ID+当前选中声音序号（序号大于等于当前声音序号声音列表），按照序号正序排-得到“待购”声音集合  limit count 有可能包含已购声音
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId());
        queryWrapper.ge(TrackInfo::getOrderNum, trackInfo.getOrderNum());
        queryWrapper.last("limit " + trackCount);
        List<TrackInfo> waitBuyTrackInfoList = trackInfoMapper.selectList(queryWrapper);

        //3.远程调用“用户服务”根据专辑id获取用户的声音列表
        List<Long> userPaidTrackList = userFeignClient.getUserPaidTrackList(trackInfo.getAlbumId()).getData();

        //4.将已购声音ID排除到分集购买以外
        if (CollectionUtil.isNotEmpty(userPaidTrackList)) {
            waitBuyTrackInfoList =
                    waitBuyTrackInfoList.stream().filter(trackInfo1 -> !userPaidTrackList.contains(trackInfo1.getId())).collect(Collectors.toList());
        }
        return waitBuyTrackInfoList;
    }
}
